package manager;

import model.Category;
import model.User;
import dao.CategoryDAO;
import java.util.*;

import org.hibernate.Session;

import util.HibernateSessionFactory;

/**
 * manageing the category, using singleton
 * 
 * @author xbingo
 * 
 */
public class CategoryManager {
	private static CategoryManager categoryManager = new CategoryManager();
	private static CategoryDAO categoryDao = new CategoryDAO();

	private CategoryManager() {
	}

	/**
	 * get the instance of CategoryManager
	 * 
	 * @return
	 */
	public static CategoryManager getCategoryManager() {
		return categoryManager;
	}

	/**
	 * get the data access object for Category
	 * 
	 * @return
	 */
	public CategoryDAO getCategoryDAO() {
		return categoryDao;
	}

	/**
	 * construct a default category
	 * 
	 * @return default category
	 */
	public Category getDefaultCategory() {
		Category defaultCategory = new Category();
		defaultCategory.setName("default");
		return defaultCategory;
	}

	/**
	 * save a category, without commit the transaction
	 * 
	 * @param category
	 */
	public void save(Category category) {
		getCategoryDAO().save(category);
	}

	/**
	 * rename a category from oldName to newName
	 * 
	 * @param user
	 * @param oldName
	 * @param newName
	 * @throws DefaultCategoryCouldNotModifiedException
	 * @throws CategoryNotFoundException
	 * @throws CategoryAlreadyExistsException 
	 */
	public void rename(User user, String oldName, String newName)
			throws DefaultCategoryCouldNotModifiedException,
			CategoryNotFoundException, CategoryAlreadyExistsException {
		if (oldName.equals(getDefaultCategory().getName())) {
			throw new DefaultCategoryCouldNotModifiedException();
		}
		Category category = find(user, oldName);
		if (category == null) {
			throw new CategoryNotFoundException();
		}
		if (find(user, newName) != null){
			throw new CategoryAlreadyExistsException();
		}
		category.setName(newName);
		Session session = HibernateSessionFactory.getSession();
		session.beginTransaction();
		getCategoryDAO().attachDirty(category);
		session.getTransaction().commit();
	}

	/**
	 * add a new category
	 * 
	 * @param user
	 * @param categoryName
	 * @throws CategoryAlreadyExistsException
	 */
	public void add(User user, String categoryName)
			throws CategoryAlreadyExistsException {
		if (find(user, categoryName) != null) {
			throw new CategoryAlreadyExistsException();
		}

		Category category = new Category();
		category.setName(categoryName);
		category.setUser(user);
		user.getCategories().add(category);
		Session session = HibernateSessionFactory.getSession();
		session.beginTransaction();
		save(category);
		session.getTransaction().commit();
	}

	/**
	 * Find category belongs to user and named categoryName
	 * 
	 * @param user
	 * @param categoryName
	 * @return return the category, return null if that category is not found
	 */
	public Category find(User user, String categoryName) {
		Iterator<Category> it = user.getCategories().iterator();
		while (it.hasNext()) {
			Category c = it.next();
			if (c.getName().equals(categoryName)) {
				return c;
			}
		}
		return null;
	}

	/**
	 * remove a category
	 * 
	 * @param user
	 * @param categoryName
	 * @throws DefaultCategoryCouldNotModifiedException
	 * @throws CategoryNotFoundException
	 */
	public void remove(User user, String categoryName)
			throws DefaultCategoryCouldNotModifiedException,
			CategoryNotFoundException {
		if (categoryName.equals(getDefaultCategory().getName())) {
			throw new DefaultCategoryCouldNotModifiedException();
		}
		Category category = find(user, categoryName);
		if (category == null) {
			throw new CategoryNotFoundException();
		}
		user.getCategories().remove(category);
		Session session = HibernateSessionFactory.getSession();
		session.beginTransaction();
		categoryDao.delete(category);
		session.getTransaction().commit();
	}
}
